﻿/*
 * Copyright 2012 Rene Prost, Registrite ja Infosüsteemide Keskus 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Xtee.Core.Adapter.Service.Config;
using Xtee.Core.Envelope.Header;
using Xtee.Core.Types;

namespace Xtee.Core.Envelope
{ 
    public class SoapEnvelope :  ISoapEnvelope, IDisposable {


        private IHeader @__header;

        private object @__body;

        public SoapEnvelope() {

        }
        
        /// <summary>
        /// All parameters
        /// </summary>
        public SoapEnvelope(XmlQualifiedName targetNamespace, List<XmlQualifiedName> otherNamespaceDeclarations, string operationName, IHeader @header, object @body)
        {
            TargetNamespace = targetNamespace;
            OperationName = operationName;
            OtherNamespaceDeclarations = otherNamespaceDeclarations;
            
            @__header = @header;
            @__body = @body;
        }
        /// <summary>
        /// All parameters
        /// </summary>
        public SoapEnvelope(string operationName, IHeader @header, object @body)
        {
            OperationName = operationName; 
            @__header = @header;
            @__body = @body;
        }
        public SoapEnvelope(string operationName, IHeader header):this(operationName,header,null){}
        /// <summary>
        /// Copy Constructor
        /// </summary>
        protected SoapEnvelope(ISoapEnvelope soapEnvelope) {
            @__header = soapEnvelope.Header;
            @__body = soapEnvelope.Body;
            OperationName = soapEnvelope.OperationName;
            TargetNamespace = soapEnvelope.TargetNamespace;
        }
        
        public virtual IHeader Header
        {
            get {
                return this.@__header;
            }
            set {
                this.@__header = value;
            }
        }

        public MemoryStream HeaderStream { get; set; }

        public virtual object Body
        {
            get {
                return this.@__body;
            }
            set {
                this.@__body = value;
            }
        }
        public bool IsFault { get; private set; }
        public bool IsRequestEnvelope { get; private set; }
        public string OperationName { get; set; }

        #region ISoapEnvelope Members

        public XmlQualifiedName TargetNamespace { get; set; }
        public List<XmlQualifiedName> OtherNamespaceDeclarations { get; set; } = new List<XmlQualifiedName>();
        public string TargetNamespaceURI { get; set; }
        public IXteeOperationInfo Operation
        {
            get
            {
                if (Header  == null /*|| string.IsNullOrEmpty(Header.GetServiceName())*/)
                    return null;

                return XteeOperationConfigElement.Parse(Header.Service);

            }
        }

        public Type HeaderType { get; private set; }
        public Type MessageType { get; private set; }

        public void Init(Stream stream)
        {
            var reader = XteeXmlReader.Create(stream);
            reader.MoveToBody();
            IsRequestEnvelope = !reader.LocalName.EndsWith("Response");
            TargetNamespaceURI = reader.NamespaceURI;

            OperationName = IsRequestEnvelope ? reader.LocalName : reader.LocalName.Remove(reader.LocalName.Length - 8, 8); //xtee häkid 

            Type messageType;
            Type headerType;

            GetOperationMessageAndHeaderType(IsRequestEnvelope, new XmlQualifiedName(OperationName, TargetNamespaceURI), out messageType, out headerType);

            if (headerType != null)
            {
                Header = (IHeader)Activator.CreateInstance(headerType);
            }
            
            Body = Activator.CreateInstance(messageType);
            stream.Position = 0;
        }

        protected void GetOperationMessageAndHeaderType(bool ofinput, XmlQualifiedName qualifiedName, out Type messageType, out Type headerType)
        {
            AbstractXteeSerializable.Validate(qualifiedName);
            var op = SerializationMetaRegistry.GetOperation(qualifiedName);
            if (op == null)
                throw new Exception("Couldn't find meta information of operation [" + qualifiedName.Name + "] )");

            if (ofinput)
            {
                messageType= op.InputMessageType;
                headerType = op.InputHeaderType;
            }
            else
            {
                messageType = op.OutputMessageType;
                headerType = op.OutputHeaderType;
            }
                
        }

        #endregion

        public void Dispose()
        {
            HeaderStream.Dispose();
        }
    }
}
